"""
企业级反爬虫中间件 - 针对多用户公司环境优化
"""

import re
import logging
from django.http import JsonResponse
from django.core.cache import cache
from django.utils.deprecation import MiddlewareMixin
from django.conf import settings
import time
from datetime import datetime, timedelta

logger = logging.getLogger(__name__)

class EnterpriseAntiCrawlerMiddleware(MiddlewareMixin):
    """企业级反爬虫中间件 - 针对多用户环境优化"""
    
    # 公司IP白名单（可配置多个公司网段）
    COMPANY_IP_RANGES = [
        '127.0.0.1', 'localhost', '::1',  # 本地IP
        '49.233.138.141',  # 生产服务器IP
        '112.97.192.192',   # 管理员IP - 已加入白名单
        
        # 🏢 添加你们公司的IP地址（请根据实际情况修改）
        # 方式1: 单个固定IP
        # '123.456.789.101',  # 公司固定IP1
        # '123.456.789.102',  # 公司固定IP2
        
        # 方式2: IP网段 (推荐用于公司内网)
        '192.168.1.0/24',    # 公司内网A段 (192.168.1.1-192.168.1.254)
        '192.168.2.0/24',    # 公司内网B段 (192.168.2.1-192.168.2.254)
        # '10.0.0.0/16',       # 公司内网C段 (10.0.0.1-10.0.255.254)
        
        # 方式3: 公司出口IP (员工在家办公也适用)
        # '111.222.333.444',   # 公司出口IP
    ]
    
    # 爬虫User-Agent黑名单
    CRAWLER_USER_AGENTS = [
        r'.*bot.*', r'.*crawl.*', r'.*spider.*', r'.*scrape.*',
        r'python-requests.*', r'urllib.*', r'curl.*', r'wget.*',
        r'scrapy.*', r'selenium.*', r'phantomjs.*', r'headless.*',
        r'postman.*', r'insomnia.*', r'httpie.*', r'.*scan.*',
    ]
    
    # 合法浏览器User-Agent白名单
    ALLOWED_USER_AGENTS = [
        r'.*chrome.*', r'.*firefox.*', r'.*safari.*', r'.*edge.*',
        r'.*opera.*', r'.*internet explorer.*', r'.*msie.*',
        # 移动端浏览器
        r'.*mobile.*safari.*', r'.*android.*', r'.*iphone.*', r'.*ipad.*',
        # 社交应用内置浏览器
        r'.*micromessenger.*',  # 微信浏览器
        r'.*wechat.*',          # 微信浏览器
        r'.*qq.*',              # QQ浏览器
        r'.*weibo.*',           # 微博浏览器
        r'.*facebook.*',        # Facebook浏览器
        r'.*messenger.*',       # Facebook Messenger
        r'.*twitter.*',         # Twitter浏览器
        r'.*instagram.*',       # Instagram浏览器
        r'.*line.*',            # Line浏览器
        r'.*telegram.*',        # Telegram浏览器
        r'.*whatsapp.*',        # WhatsApp浏览器
        # 其他常见移动应用
        r'.*app.*',             # 通用App
        r'.*mobile.*',          # 移动设备
        r'.*tablet.*',          # 平板设备
    ]
    
    def __init__(self, get_response):
        self.get_response = get_response
        super().__init__(get_response)
    
    def process_request(self, request):
        """处理请求"""
        
        # 开发环境完全放行本地IP
        from django.conf import settings as django_settings
        if getattr(django_settings, 'DEBUG', False):
            ip_address = self.get_client_ip(request)
            if ip_address in ['127.0.0.1', 'localhost', '::1']:
                return None  # 开发环境本地IP完全放行
        
        # 获取客户端信息
        user_agent = request.META.get('HTTP_USER_AGENT', '').lower()
        ip_address = self.get_client_ip(request)
        
        # 检查公司IP白名单
        if self.is_company_ip(ip_address):
            # 公司IP放宽限制，但仍检测明显的爬虫行为
            if self.is_obvious_crawler(user_agent):
                logger.warning(f"公司IP检测到明显爬虫行为: {user_agent} from {ip_address}")
                return JsonResponse({
                    'error': '检测到异常访问模式，请使用正常浏览器访问',
                    'code': 'COMPANY_CRAWLER_DETECTED'
                }, status=403)
            return None  # 公司IP其他情况直接放行
        
        # 外部IP严格检查
        # 记录请求
        self.log_request(request, ip_address, user_agent)
        
        # 检查IP黑名单
        if self.is_ip_blocked(ip_address):
            logger.warning(f"黑名单IP访问被拒绝: {ip_address}")
            return JsonResponse({
                'error': '访问被拒绝',
                'code': 'ACCESS_DENIED'
            }, status=403)
        
        # User-Agent检测
        if self.is_crawler_user_agent(user_agent):
            logger.warning(f"检测到爬虫User-Agent: {user_agent} from {ip_address}")
            self.block_ip_temporarily(ip_address, reason="crawler_user_agent")
            return JsonResponse({
                'error': '访问被拒绝',
                'code': 'CRAWLER_DETECTED'
            }, status=403)
        
        # 频率检测（外部IP）
        if self.check_rate_limit_external(ip_address, request.path):
            logger.warning(f"外部IP {ip_address} 访问频率过高")
            self.block_ip_temporarily(ip_address, reason="rate_limit_exceeded")
            return JsonResponse({
                'error': '访问频率过高，请稍后再试',
                'code': 'RATE_LIMIT_EXCEEDED'
            }, status=429)
        
        return None
    
    def get_client_ip(self, request):
        """获取客户端真实IP"""
        x_forwarded_for = request.META.get('HTTP_X_FORWARDED_FOR')
        if x_forwarded_for:
            ip = x_forwarded_for.split(',')[0]
        else:
            ip = request.META.get('REMOTE_ADDR')
        return ip
    
    def is_company_ip(self, ip_address):
        """检查是否为公司IP"""
        return ip_address in self.COMPANY_IP_RANGES
    
    def is_obvious_crawler(self, user_agent):
        """检测明显的爬虫行为（用于公司IP检查）"""
        if not user_agent:
            return True
        
        # 先检查是否为合法浏览器（包括社交应用浏览器）
        for pattern in self.ALLOWED_USER_AGENTS:
            if re.match(pattern, user_agent, re.IGNORECASE):
                return False  # 合法浏览器，不是爬虫
        
        # 只检测最明显的爬虫特征
        obvious_crawlers = [
            r'python-requests.*', r'urllib.*', r'wget.*', r'curl.*',
            r'scrapy.*', r'.*bot.*', r'.*spider.*', r'.*crawl.*'
        ]
        
        for pattern in obvious_crawlers:
            if re.match(pattern, user_agent, re.IGNORECASE):
                return True
        return False
    
    def is_crawler_user_agent(self, user_agent):
        """检测是否为爬虫User-Agent（外部IP严格检查）"""
        if not user_agent:
            return True
        
        # 检查黑名单
        for pattern in self.CRAWLER_USER_AGENTS:
            if re.match(pattern, user_agent, re.IGNORECASE):
                return True
        
        # 检查是否在白名单中
        for pattern in self.ALLOWED_USER_AGENTS:
            if re.match(pattern, user_agent, re.IGNORECASE):
                return False
        
        return True
    
    def is_ip_blocked(self, ip_address):
        """检查IP是否被屏蔽"""
        blocked_key = f"blocked_ip:{ip_address}"
        return cache.get(blocked_key) is not None
    
    def block_ip_temporarily(self, ip_address, reason="unknown", duration=None):
        """临时屏蔽IP"""
        if duration is None:
            if reason == "crawler_user_agent":
                duration = 900   # 爬虫User-Agent: 15分钟
            elif reason == "rate_limit_exceeded":
                duration = 180   # 频率超限: 3分钟
            else:
                duration = 300   # 其他原因: 5分钟
        
        blocked_key = f"blocked_ip:{ip_address}"
        blocked_info = {
            'reason': reason,
            'blocked_at': datetime.now().isoformat(),
            'ip': ip_address,
            'duration': duration
        }
        cache.set(blocked_key, blocked_info, duration)
        logger.warning(f"IP {ip_address} 被临时屏蔽 {duration}秒，原因: {reason}")
    
    def check_rate_limit_external(self, ip_address, path):
        """检查外部IP访问频率限制"""
        current_time = int(time.time())
        
        # 外部IP更严格的限制
        if path.startswith('/api/'):
            if 'login' in path:
                # 登录接口：3次/分钟（外部IP严格限制）
                return self._check_limit(ip_address, 'ext_login', 3, 60)
            elif 'schedules' in path or 'vessel-info' in path:
                # 船期查询接口：10次/分钟（外部IP限制）
                return self._check_limit(ip_address, 'ext_schedule_api', 10, 60)
            else:
                # 其他API：30次/分钟（外部IP限制）
                return self._check_limit(ip_address, 'ext_general_api', 30, 60)
        
        return False
    
    def _check_limit(self, ip_address, api_type, max_requests, window_seconds):
        """检查特定类型API的访问限制"""
        cache_key = f"rate_limit:{ip_address}:{api_type}"
        current_time = int(time.time())
        window_start = current_time - window_seconds
        
        # 获取当前时间窗口内的请求记录
        request_times = cache.get(cache_key, [])
        
        # 清理过期的请求记录
        request_times = [t for t in request_times if t > window_start]
        
        # 检查是否超过限制
        if len(request_times) >= max_requests:
            return True
        
        # 记录当前请求
        request_times.append(current_time)
        cache.set(cache_key, request_times, window_seconds)
        
        return False
    
    def log_request(self, request, ip_address, user_agent):
        """记录请求信息（只记录外部IP）"""
        log_key = f"request_log:{ip_address}:{int(time.time())}"
        log_data = {
            'ip': ip_address,
            'user_agent': user_agent,
            'path': request.path,
            'method': request.method,
            'timestamp': datetime.now().isoformat(),
        }
        
        # 记录到缓存（24小时）
        cache.set(log_key, log_data, 86400)
        
        # 记录到日志文件
        logger.info(f"外部IP请求: {ip_address} {request.method} {request.path} UA: {user_agent[:100]}")


class SecurityHeadersMiddleware(MiddlewareMixin):
    """安全头部中间件"""
    
    def __init__(self, get_response):
        self.get_response = get_response
        super().__init__(get_response)
    
    def process_response(self, request, response):
        """添加安全头部"""
        
        # 添加安全头部
        response['X-Content-Type-Options'] = 'nosniff'
        response['X-Frame-Options'] = 'DENY'
        response['X-XSS-Protection'] = '1; mode=block'
        response['Referrer-Policy'] = 'strict-origin-when-cross-origin'
        
        # API响应禁用缓存
        if request.path.startswith('/api/'):
            response['Cache-Control'] = 'no-cache, no-store, must-revalidate'
            response['Pragma'] = 'no-cache'
            response['Expires'] = '0'
        
        return response